﻿using LightCAD.Core;
using LightCAD.Core.Element3d;
using LightCAD.Core.Elements;
using LightCAD.Drawing;
using LightCAD.Drawing.Actions;
using LightCAD.MathLib;
using LightCAD.Model;
using LightCAD.Runtime;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static LightCAD.Core.Element3d.LcLoftDef;
using Constants = LightCAD.Runtime.Constants;

namespace LightCAD.Component.Actions
{
    public class LoftAction : ComponentInstance2dAction
    {
        public static LcCreateMethod[] CreateMethods;

        /// <summary>
        /// 轮廓第一个点
        /// </summary>
        private Vector2? firstPoint { get; set; }

        /// <summary>
        /// 外轮廓
        /// </summary>
        private List<Curve2d> Segments { get; set; }

        /// <summary>
        /// 当前绘制线段类型
        /// </summary>
        private string CurrentType = "Line";
        /// <summary>
        /// 当前圆心画圆曲线
        /// </summary>
        private Arc2d CurrentArc;

        private LcLoftDef loftDef;
        private LcLoftInstance loft;
        static LoftAction()
        {
            CreateMethods = new LcCreateMethod[1]; 
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "CreatePath",
                Description = "创建轮廓",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep { Name=  "Step0", Options= "指定起点:" },
                    new LcCreateStep { Name=  "Stea", Options= "下一个点或[圆弧(A):" },
                    new LcCreateStep { Name=  "Steb", Options= "下一个点或[圆弧(A)/闭合(C)/创建完成(O)/]:" },
                    new LcCreateStep { Name=  "Step3", Options= "[角度(A)/圆心(CE)/半径(R)/第二个点(S)/直线(L)/创建完成(O)]:" },
                    new LcCreateStep { Name=  "Step4", Options= "[角度(A)/圆心(CE)/闭合(CL)/直线(L)/半径(R)/第二个点(S)/创建完成(O)]:" },
                    new LcCreateStep { Name=  "Step5", Options= "指定圆弧的圆心:" },
                    new LcCreateStep { Name=  "Step6", Options= "指定圆弧的端点或 [角度(A)/长度(L)/切换方向(C)/]:" },
                }
            };
        }

        private PointInputer PointInputer { get; set; }

        public LoftAction() : base()
        {

        }
        public LoftAction(IDocumentEditor docEditor) : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令：Loft");
        }
        public async void ExecCreate(string[] args = null)
        {
            var win = (ILoftDefWindow)AppRuntime.UISystem.CreateWindow("LoftDefSelect");
            var result = AppRuntime.UISystem.ShowDialog(win);
            if (result != LcDialogResult.OK)
            {
                return;
            }
            loftDef = ComponentManager.GetCptDef<LcLoftDef>("放样体", "放样体", win.Uuid);

            this.StartCreating();
            StartPathEditing();
            var curMethod = CreateMethods[0];
            this.PointInputer = new PointInputer(this.docEditor);

            var succes = await Creating(curMethod, Segments);
            if (succes)
            {
                CreateOrUpdateLoft();
            }

        End:
            Segments = null;
            CurrentArc = null;
            this.PointInputer = null;
            this.vportRt.CloseSectionEditing();
            this.Cancel();
            this.EndCreating();
        }
        private void StartPathEditing()
        {
            this.Segments = new List<Curve2d>();
            //this.vportRt.SectionEditingObject = new SectionEditingObject() { };
            //this.vportRt.SectionEditingObject.Initilize(this.docRt.Document);
            //this.vportRt.StartSectionEditing();
        }
        private async Task<bool> Creating(LcCreateMethod curMethod, List<Curve2d> curSg)
        {
        Step0:
            this.CurrentType = "Line";
            var step0 = curMethod.Steps[0];
            var result0 = await PointInputer.Execute(step0.Options);
            if (PointInputer.isCancelled || result0.ValueX == null)
            {
                return false;
            }
            this.firstPoint = (Vector2)result0.ValueX;
        Stea:
            this.CurrentType = "Line";
            var stea = curMethod.Steps[1];
            var result1 = await PointInputer.Execute(stea.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
            if (result1.ValueX != null)
            {
                Vector2 pointB = (Vector2)result1.ValueX;
                Line2d pline = new Line2d();
                if (curSg.Count > 0)
                {
                    var lastLine = curSg.Last();
                    var endPoint = lastLine is Line2d ? (lastLine as Line2d).End : (lastLine as Arc2d).GetPoints(1).Last();
                    pline.Start = endPoint.Clone();
                }
                else
                {
                    pline.Start = this.firstPoint.Clone();
                }
                pline.End = pointB.Clone();
                curSg.Add(pline);
                if (curSg.Count > 0)
                {
                    CreateOrUpdateLoft();
                    goto Steb;
                }
                goto Stea;
            }
            else if (result1.Option != null)
            {
                if (result1.Option.ToUpper() == "A")
                {
                    goto Step3;
                }
                //else if(result1.Option.ToUpper() == "O")
                //{
                //    return true;
                //}
                else
                {
                    goto Stea;
                }
            }
            goto Stea;
        Steb:
            this.CurrentType = "Line";
            var steb = curMethod.Steps[2];
            var result2 = await PointInputer.Execute(steb.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
            if (result2.ValueX != null)
            {
                Vector2 pointB = (Vector2)result2.ValueX;
                Line2d pline = new Line2d();
                var lastLine = curSg.Last();
                var endPoint = lastLine is Line2d ? (lastLine as Line2d).End : (lastLine as Arc2d).GetPoints(1).Last();
                pline.Start = endPoint.Clone();
                pline.End = pointB.Clone();
                curSg.Add(pline);
                if (curSg.Last().GetPoints(1).Last().DistanceTo(curSg.First().GetPoints(1).First()) == 0)
                {
                    return true;
                }
                CreateOrUpdateLoft();
                goto Steb;
            }
            else if (result2.Option != null)
            {
                if (result2.Option.ToUpper() == "A")
                {
                    if (curSg.Count >= 2 || curSg.Any(n => n is Arc2d))
                        goto Step4;
                    else
                        goto Step3;
                }
                else if (result2.Option.ToUpper() == "C")
                {
                    Line2d pline = new Line2d();
                    var lastLine = curSg.Last();
                    var first = curSg.First();
                    var endPoint = lastLine is Line2d ? (lastLine as Line2d).End : (lastLine as Arc2d).GetPoints(1).Last();
                    var startPoint = first is Line2d ? (first as Line2d).Start : (first as Arc2d).GetPoints(1).First();
                    pline.Start = endPoint.Clone();
                    pline.End = startPoint.Clone();
                    curSg.Add(pline);
                    return true;
                }
                else if (result2.Option.ToUpper() == "O")
                {
                    return true;
                }
            }
            goto Steb;
        Step3:
            this.CurrentType = "Arc";
            var step3 = curMethod.Steps[3];
            var result3 = await PointInputer.Execute(step3.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
            if (result3.ValueX != null)
            {
                Vector2 currP = (Vector2)result3.ValueX;
                Vector2 lastStart, lastEnd;
                if (curSg.Count > 0)
                {
                    if (curSg.Last() is Line2d lastline)
                    {
                        lastEnd = lastline.End.Clone();
                        lastStart = lastline.Start.Clone();
                    }
                    else
                    {
                        var arc = curSg.Last() as Arc2d;
                        var arcp = arc.GetPoints(100);
                        lastEnd = arcp.Last().Clone();
                        lastStart = arcp[98].Clone();
                    }
                }
                else
                {
                    lastStart = new(this.firstPoint.X - 5, this.firstPoint.Y);
                    lastEnd = this.firstPoint.Clone();
                }

                var cir = GetCircleBylinePoint(lastStart, lastEnd, currP);
                if (cir == null)
                {
                    Line2d line = new Line2d();
                    line.Start = lastEnd;
                    line.End = currP;
                    curSg.Add(line);
                    CreateOrUpdateLoft();
                    goto Step3;
                }
                else
                {
                    var arc = new Arc2d();
                    arc.Center = cir.Item1;
                    arc.Radius = Vector2.Distance(cir.Item1, currP);
                    var angle = currP.Clone().Sub(lastEnd).Angle() - lastStart.Clone().Sub(lastEnd).Angle();
                    arc.IsClockwise = angle < -Math.PI || (angle > 0 && angle < Math.PI);
                    arc.StartAngle = lastEnd.Clone().Sub(arc.Center).Angle();
                    arc.EndAngle = currP.Clone().Sub(arc.Center).Angle();
                    if (double.IsNaN(arc.StartAngle) || double.IsNaN(arc.EndAngle))
                    {
                        if (curSg.Count > 1)
                        {
                            goto Step4;
                        }
                        else
                        {
                            goto Step3;
                        }
                    }
                    curSg.Add(arc);
                    CreateOrUpdateLoft();
                    goto Step4;
                }
            }
            else if (result3.Option != null)
            {
                if (result3.Option.ToUpper() == "L")
                {
                    goto Stea;
                }
                else if (result3.Option.ToUpper() == "CE")
                {
                    goto Step5;
                }
                else if (result3.Option.ToUpper() == "O")
                {
                    return true;
                }
            }
            goto Step3;
        Step4:
            this.CurrentType = "Arc";
            var step4 = curMethod.Steps[4];
            var result4 = await PointInputer.Execute(step4.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
            if (result4.ValueX != null)
            {
                Vector2 currP = (Vector2)result4.ValueX;
                Vector2 lastEnd, lastStart;
                if (curSg.Last() is Line2d lastline)
                {
                    lastEnd = lastline.End.Clone();
                    lastStart = lastline.Start.Clone();
                }
                else
                {
                    var arc = curSg.Last() as Arc2d;
                    var arcp = arc.GetPoints(100);
                    lastEnd = arcp.Last().Clone();
                    lastStart = arcp[98].Clone();
                }

                var cir = GetCircleBylinePoint(lastStart, lastEnd, currP);
                if (cir == null)
                {
                    Line2d line = new Line2d();
                    line.Start = lastEnd;
                    line.End = currP;
                    curSg.Add(line);
                }
                else
                {
                    var arc = new Arc2d();
                    arc.Center = cir.Item1;
                    //arc.Angle = cir.Item3;
                    arc.Radius = Vector2.Distance(cir.Item1, currP);
                    var angle = currP.Clone().Sub(lastEnd).Angle() - lastStart.Clone().Sub(lastEnd).Angle();
                    arc.IsClockwise = angle < -Math.PI || (angle > 0 && angle < Math.PI);
                    arc.StartAngle = lastEnd.Clone().Sub(arc.Center).Angle();
                    arc.EndAngle = currP.Clone().Sub(arc.Center).Angle();
                    if (double.IsNaN(arc.StartAngle) || double.IsNaN(arc.EndAngle))
                    {
                        goto Step4;
                    }
                    curSg.Add(arc);
                }
                if (curSg.Last().GetPoints(1).Last().DistanceTo(curSg.First().GetPoints(1).First()) == 0)
                {
                    return true;
                }
                goto Step4;

            }
            else if (result4.Option != null)
            {
                if (result4.Option.ToUpper() == "L")
                {
                    goto Steb;
                }
                else if (result4.Option.ToUpper() == "CL")
                {
                    Vector2 lastStart, lastEnd;
                    var firstLine = curSg.First();
                    if (curSg.Last() is Line2d lastline)
                    {
                        lastEnd = lastline.End.Clone();
                        lastStart = lastline.Start.Clone();
                    }
                    else
                    {
                        var arc = curSg.Last() as Arc2d;
                        var arcp = arc.GetPoints(100);
                        lastEnd = arcp.Last().Clone();
                        lastStart = arcp[98].Clone();
                    }
                    var fsp = (firstLine is Line2d ? (firstLine as Line2d).Start : (firstLine as Arc2d).GetPoints(1).First()).Clone();
                    //Line2d line = new Line2d();
                    //line.Start = lep.Clone();
                    //line.End = fsp.Clone();
                    var cir = GetCircleBylinePoint(lastStart, lastEnd, fsp);
                    if (cir == null)
                    {
                        Line2d line = new Line2d();
                        line.Start = lastEnd;
                        line.End = fsp;
                        curSg.Add(line);
                    }
                    else
                    {
                        var arc = new Arc2d();
                        arc.Center = cir.Item1;
                        //arc.Angle = cir.Item3;
                        arc.Radius = Vector2.Distance(cir.Item1, fsp);
                        var angle = fsp.Clone().Sub(lastEnd).Angle() - lastStart.Clone().Sub(lastEnd).Angle();
                        arc.IsClockwise = angle < -Math.PI || (angle > 0 && angle < Math.PI);
                        arc.StartAngle = lastEnd.Clone().Sub(arc.Center).Angle();
                        arc.EndAngle = fsp.Clone().Sub(arc.Center).Angle();
                        if (double.IsNaN(arc.StartAngle) || double.IsNaN(arc.EndAngle))
                        {
                            goto Step4;
                        }
                        curSg.Add(arc);
                    }
                    return true;
                }
                else if (result4.Option.ToUpper() == "CE")
                {
                    goto Step5;
                }
                else if (result4.Option.ToUpper() == "O")
                {
                    return true;
                }
            }
            goto Step4;
        Step5:
            this.CurrentType = "Arc-CE";
            var step5 = curMethod.Steps[5];
            var result5 = await PointInputer.Execute(step5.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
            if (result5.ValueX != null)
            {
                CurrentArc = new Arc2d();
                Vector2 center = (Vector2)result5.ValueX;
                CurrentArc.Center = center.Clone();
                Vector2 lastEnd;
                if (curSg.Count > 0)
                {
                    var lastLine = curSg.Last();
                    var endPoint = lastLine is Line2d ? (lastLine as Line2d).End : (lastLine as Arc2d).GetPoints(1).Last();
                    lastEnd = endPoint.Clone();
                }
                else
                {
                    lastEnd = this.firstPoint.Clone();
                }
                CurrentArc.Radius = center.DistanceTo(lastEnd);
                CurrentArc.StartAngle = lastEnd.Clone().Sub(center).Angle();
                goto Step6;
            }
            goto Step5;
        Step6:
            var step6 = curMethod.Steps[6];
            var result6 = await PointInputer.Execute(step6.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
            if (result6.ValueX != null)
            {
                Vector2 end = (Vector2)result6.ValueX;
                CurrentArc.EndAngle = end.Clone().Sub(CurrentArc.Center).Angle();
                curSg.Add(CurrentArc.Clone());
                CurrentArc = null;
                goto Step4;
            }
            else if (result6.Option != null)
            {
                if (result6.Option.ToUpper() == "C")
                {
                    CurrentArc.IsClockwise = !CurrentArc.IsClockwise;
                }
            }
            goto Step6;
        }

        private void CreateOrUpdateLoft()
        {
            var insertPoint = this.Segments[0].GetPoints(2)[0];
            var segments = this.Segments.Select(s => s.Clone().Translate(insertPoint.Clone().Negate())).ToList();
            if (this.loft != null)
            {
                //this.docRt.Document.ModelSpace.RemoveElement(this.loft);
                this.loft.OnPropertyChangedBefore("Path", null, null);
                this.loft.Parameters["Path"] = segments;
                this.loft.ResetCache();
                this.loft.UpdateTransformMatrix();
                this.loft.OnPropertyChangedAfter("Path", null, null);
                return;
            }
            var mats = new LcMaterial[1]
            {
                new LcMaterial() { Color = new Color(0xff0000) },
            };
            loft = new LcLoftInstance(segments, loftDef);
            loft.Initilize(this.docRt.Document);
            //(loft.Rt3DAction as IComponentAction).SetDocEditor(this.docEditor);
            loft.Position.Set(insertPoint.X, insertPoint.Y, 0);
            this.docRt.Document.ModelSpace.InsertElement(loft);
        }

        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            base.Draw(canvas, element, matrix);
            return;
            var pen = this.GetDrawPen(element);
            for (int i = 0; i < this.Segments.Count; i++)
            {
                var curve = this.Segments[i];
                if (curve is Line2d curLine)
                {
                    var mstart = curLine.Start;
                    var mend = curLine.End;
                    var start = this.vportRt.ConvertWcsToScr(mstart).ToSKPoint();
                    var end = this.vportRt.ConvertWcsToScr(mend).ToSKPoint();

                    if (pen == Constants.defaultPen)
                    {
                        //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                        using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                        {
                            canvas.DrawLine(start, end, elePen);
                        }
                    }
                    else
                    {
                        canvas.DrawLine(start, end, pen);
                    }
                }
                else if (curve is Arc2d arc)
                {
                    if (pen == Constants.defaultPen)
                    {
                        //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                        using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                        {
                            this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                        }
                    }
                    else
                    {
                        this.vportRt.DrawArc(arc, matrix, canvas, pen);
                    }

                }

            }
        }
        public override void DrawTemp(SKCanvas canvas)
        {

        }
        public override void DrawAuxLines(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            var sk_p = this.vportRt.ConvertWcsToScr(wcs_mp).ToSKPoint();

            foreach (var ele in this.Segments)
            {
                if (ele is Line2d line)
                {
                    var start = this.vportRt.ConvertWcsToScr(line.Start).ToSKPoint();
                    var end = this.vportRt.ConvertWcsToScr(line.End).ToSKPoint();
                    using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                    {
                        canvas.DrawLine(start, end, elePen);
                    }
                }
                else if (ele is Arc2d arc)
                {
                    using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                    {
                        Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                        this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                    }
                }
            }

            Vector2 startpoint = new Vector2(0, 0);//上一个元素的开始点
            Vector2 lastStart;
            if (this.firstPoint == null)
                return;

            if (Segments.Count == 0)
            {
                startpoint = this.firstPoint.Clone();
                lastStart = new Vector2(this.firstPoint.X - 5, this.firstPoint.Y);
            }
            else
            {
                if (Segments.Last() is Line2d lastline)
                {
                    startpoint = lastline.End.Clone();
                    lastStart = lastline.Start.Clone();
                }
                else
                {
                    var arc = Segments.Last() as Arc2d;
                    var arcp = arc.GetPoints(100);
                    startpoint = arcp.Last().Clone();
                    lastStart = arcp[98].Clone();
                }
            }

            if (CurrentType == "Arc")
            {
                var cir = GetCircleBylinePoint(lastStart, startpoint, wcs_mp);
                if (cir == null)
                {
                    using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                    {
                        canvas.DrawLine(this.vportRt.ConvertWcsToScr(startpoint).ToSKPoint(), sk_p, elePen);
                    }
                    return;
                }
                var arc = new Arc2d();
                arc.Center = cir.Item1.Clone();
                arc.Radius = startpoint.DistanceTo(arc.Center);
                var angle = wcs_mp.Clone().Sub(startpoint).Angle() - lastStart.Clone().Sub(startpoint).Angle();
                arc.IsClockwise = angle < -Math.PI || (angle > 0 && angle < Math.PI);
                arc.StartAngle = startpoint.Clone().Sub(arc.Center).Angle();
                arc.EndAngle = wcs_mp.Clone().Sub(arc.Center).Angle();
                if (double.IsNaN(arc.StartAngle) || double.IsNaN(arc.EndAngle))
                {
                    return;
                }
                using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                {
                    //arc.EndAngle = wcs_mp.Sub(arc.Center).Angle();
                    //var lcenter = this.vportRt.ConvertWcsToScr(arc.Center).ToSKPoint();
                    //double lradius = Math.Sqrt(Math.Pow(lcenter.X - sk_p.X, 2) + Math.Pow(lcenter.Y - sk_p.Y, 2));
                    //float lx1 = (float)(lcenter.X - lradius);
                    //float ly1 = (float)(lcenter.Y - lradius);
                    //float lx2 = (float)(lcenter.X + lradius);
                    //float ly2 = (float)(lcenter.Y + lradius);
                    Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                    this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                }
                using (var elePen = new SKPaint { Color = SKColors.Yellow, IsStroke = true, PathEffect = SKPathEffect.CreateDash(new float[] { 10, 10, 30, 10 }, 0) })
                {
                    canvas.DrawLine(this.vportRt.ConvertWcsToScr(startpoint).ToSKPoint(), sk_p, elePen);
                }
            }
            else if (CurrentType == "Arc-CE")
            {
                if (CurrentArc == null)
                {
                    using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                    {
                        canvas.DrawLine(this.vportRt.ConvertWcsToScr(startpoint).ToSKPoint(), sk_p, elePen);
                    }
                }
                else
                {
                    using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                    {
                        Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                        var arc = CurrentArc.Clone() as Arc2d;
                        arc.EndAngle = wcs_mp.Sub(arc.Center).Angle();
                        this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                        //var lcenter =  this.vportRt.ConvertWcsToScr(arc.Center).ToSKPoint();
                        //double lradius = Math.Sqrt(Math.Pow(lcenter.X - sk_p.X, 2) + Math.Pow(lcenter.Y - sk_p.Y, 2));
                        //float lx1 = (float)(lcenter.X - lradius);
                        //float ly1 = (float)(lcenter.Y - lradius);
                        //float lx2 = (float)(lcenter.X + lradius);
                        //float ly2 = (float)(lcenter.Y + lradius);
                        //SKRect lskrect = new SKRect(lx1, ly1, lx2, ly2);
                        //canvas.DrawArc(lskrect,(float)arc.StartAngle, (float)arc.EndAngle,false,elePen);
                    }
                }
            }
            else
            {
                using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                {
                    canvas.DrawLine(this.vportRt.ConvertWcsToScr(startpoint).ToSKPoint(), sk_p, elePen);
                }
            }
            //base.Draw(canvas, this.loft, new Matrix3());
        }

        /// <summary>
        /// 通过圆上三点求圆心
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        private Vector2 GetCircleCenter(Vector2 a, Vector2 b, Vector2 c)
        {
            double a13 = a.X - c.X;
            double a13_ = a.X + c.X;
            double b13 = a.Y - c.Y;
            double b13_ = a.Y + c.Y;
            double a12 = a.X - b.X;
            double a12_ = a.X + b.X;
            double b12 = a.Y - b.Y;
            double b12_ = a.Y + b.Y;

            double a12b12_2 = a12 * a12_ + b12 * b12_;
            double a13b13_2 = a13 * a13_ + b13 * b13_;

            double a13b12 = 2 * a13 * b12;
            double a12b13 = 2 * a12 * b13;


            if (a12b13 - a13b12 == 0) return new Vector2((b.X + a.X) / 2, (b.Y + a.Y) / 2);
            double af = a12b13 - a13b12;
            double bf = a13b12 - a12b13;
            double az = b13 * a12b12_2 - b12 * a13b13_2;
            double bz = a13 * a12b12_2 - a12 * a13b13_2;
            double x = az / af;
            double y = bz / bf;
            return new Vector2(x, y);
        }

        public override List<PropertyObserver> GetPropertyObservers()
        {
            return new List<PropertyObserver>()
                       {
                           new PropertyObserver()
                               {
                                    Name = "LoftDefName",
                                    DisplayName = "拉伸体定义名称",
                                    CategoryName = "Geometry",
                                    CategoryDisplayName = "几何图形",
                                    Getter = (ele) => (ele as LcLoftInstance).Definition.Name
                               },
                           new PropertyObserver()
                               {
                                    Name = "Bottom",
                                    DisplayName = "底高度",
                                    CategoryName = "Geometry",
                                    CategoryDisplayName = "几何图形",
                                    Getter = (ele) => (ele as LcLoftInstance).Position.Z,
                                    Setter = (ele, value) =>
                                       {
                                           var line = (ele as LcLoftInstance);
                                           var z = Convert.ToDouble(value);
                                           line.Position.SetZ(z);
                                       }
                               },
                       };
        }
        public override Drawing.SnapPointResult SnapPoint(SnapRuntime snapRt, LcElement element, Vector2 point, bool forRef, Vector2 PrePoint = null)
        {

            var maxDistance = vportRt.GetSnapMaxDistance();
            var section = element as LcSection;
            var sscur = SnapSettings.Current;
            var result = new Drawing.SnapPointResult { Element = element };

            if (result.Point != null)
                return result;
            else
                return null;
        }
        public Tuple<Vector2, Vector2, double> GetCircleBy2PD(Vector2 start, Vector2 End, double degrees)
        {
            double point1X = start.X;
            double point1Y = start.Y;
            double point2X = End.X;
            double point2Y = End.Y;
            double angleDegrees = degrees;

            // 计算中点坐标
            double midPointX = (point1X + point2X) / 2;
            double midPointY = (point1Y + point2Y) / 2;

            // 计算两个点之间的距离
            double distance = Math.Sqrt(Math.Pow(point2X - point1X, 2) + Math.Pow(point2Y - point1Y, 2));

            // 将角度转换为弧度
            double radians = angleDegrees * Math.PI / 180;

            double radius = distance / (2 * Math.Sin(radians / 2));
            //// 计算圆心的偏移量
            //double offsetX = distance * Math.Cos(radians);
            //double offsetY = distance * Math.Sin(radians);
            double centerX = midPointX + radius * Math.Cos(radians / 2);
            double centerY = midPointY + radius * Math.Sin(radians / 2);
            // 计算圆心的坐标
            //double centerX = midPointX + offsetX;
            //double centerY = midPointY + offsetY;
            //double radius = Math.Sqrt(Math.Pow(centerX - point1X, 2) + Math.Pow(centerY - point1Y, 2));


            double dx = point2X - point1X;
            double dy = point2Y - point1Y;

            ///# 将向量差单位化
            double unit_dx = dx / distance;
            double unit_dy = dy / distance;

            ///# 计算圆心坐标
            double h = midPointX + radius * unit_dx;
            double k = midPointY + radius * unit_dy;

            var b = start;
            var a = End;
            var r = radius;

            double c1 = (b.X * b.X - a.X * a.X + b.Y * b.Y - a.Y * a.Y) / (2 * (b.X - a.X));
            double c2 = (b.Y - a.Y) / (b.X - a.X);
            double A = (c2 * c2 + 1);
            double B = (2 * a.X * c2 - 2 * c1 * c2 - 2 * a.Y);
            double C = a.X * a.X - 2 * a.X * c1 + c1 * c1 + a.Y * a.Y - r * r;
            Vector2 center1 = new Vector2();
            Vector2 center2 = new Vector2();

            center1.Y = (-B - Math.Sqrt(B * B - 4 * A * C)) / (2 * A);

            center2.Y = (-B + Math.Sqrt(B * B - 4 * A * C)) / (2 * A);

            center1.X = c1 - c2 * center1.Y;
            center2.X = c1 - c2 * center2.Y;
            return new Tuple<Vector2, Vector2, double>(center1, center2, radius);
        }
        /// <summary>
        /// 切线加终止点画弧线  返回圆心和角度
        /// </summary>
        /// <param name="lineStart"></param>
        /// <param name="lineEnd"></param>
        /// <param name="point"></param>
        /// <returns>  圆心，半径，弧度</returns>
        public Tuple<Vector2, double, double> GetCircleBylinePoint(Vector2 lineStart, Vector2 lineEnd, Vector2 point)
        {
            int tp = IsTopInLine(lineStart, lineEnd, point);
            if (tp == 0)
            {
                return null;//在同一条线上画直线
            }

            double Degrees = GetDegreesByTwoLine(lineStart, lineEnd, lineEnd, point);

            Degrees = 180 - (90 - Degrees) * 2;

            Tuple<Vector2, Vector2, double> cirTuple = GetCircleBy2PD(lineEnd, point, Degrees);
            int tc = IsTopInLine(lineEnd, point, cirTuple.Item1);
            Vector2 circenter;
            if (Degrees < 180)//圆心和线要在同一边 当弧度小于半圆，大于半圆时 ，向量反之  
            {
                if (tc == tp)
                    circenter = cirTuple.Item1;
                else circenter = cirTuple.Item2;
            }
            else
            {
                if (tc != tp)
                    circenter = cirTuple.Item1;
                else circenter = cirTuple.Item2;
            }
            /// 圆心，半径，弧度
            return new Tuple<Vector2, double, double>(circenter, cirTuple.Item3, Degrees);
        }


        /// <summary>
        /// 获取两条线的夹角  
        /// </summary>
        /// <param name="line1start"></param>
        /// <param name="line1End"></param>
        /// <param name="line2start"></param>
        /// <param name="line2End"></param>
        /// <returns></returns>
        public double GetDegreesByTwoLine(Vector2 line1start, Vector2 line1End, Vector2 line2start, Vector2 line2End)
        {
            double x1 = line1start.X;
            double y1 = line1start.Y;
            double x2 = line1End.X;
            double y2 = line1End.Y;
            double x3 = line2start.X;
            double y3 = line2start.Y;
            double x4 = line2End.X;
            double y4 = line2End.Y;

            // 计算线段的向量表示
            double v1x = x2 - x1;
            double v1y = y2 - y1;
            double v2x = x4 - x3;
            double v2y = y4 - y3;

            // 计算向量的内积
            double dotProduct = v1x * v2x + v1y * v2y;

            // 计算向量的长度
            double magnitudeV1 = Math.Sqrt(v1x * v1x + v1y * v1y);
            double magnitudeV2 = Math.Sqrt(v2x * v2x + v2y * v2y);

            // 计算夹角余弦值
            double cosine = dotProduct / (magnitudeV1 * magnitudeV2);

            // 将夹角余弦值转换为角度
            double angleRadians = Math.Acos(cosine);
            double angleDegrees = angleRadians * 180 / Math.PI;
            return angleDegrees;
        }
        public int IsTopInLine(Vector2 line1start, Vector2 line1End, Vector2 point)
        {
            Vector2 S;
            Vector2 E;
            //if (line1start.X < line1End.X)
            //{
            //    S = line1start;
            //    E = line1End;

            //}
            //else
            //   if (line1start.X == line1End.X)
            //{
            //    if (line1start.Y < line1End.Y)
            //    {
            //        S = line1start;
            //        E = line1End;

            //    }
            //    else
            //    {
            //        S = line1End;
            //        E = line1start;


            //    }
            //}
            //else
            //{
            S = line1End;
            E = line1start;

            // }
            double Tmp = (S.Y - E.Y) * point.X + (E.X - S.X) * point.Y + S.X * E.Y - E.X * S.Y;
            if (Tmp == 0)
            {
                return 0;
            }
            if (Tmp > 0)
            {
                return 1;
            }
            else
            { return -1; }
            //                Tmp > 0 在左侧

            //Tmp = 0 在线上

            //Tmp < 0 在右侧
        }
    }


    public class Loft3dAction : ComponentInstance3dAction
    {
        private LcLoftInstance loft;
        private LcLoftDef loftDef;
        public Loft3dAction(IDocumentEditor docEditor) : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令：Loft");
        }
        public Loft3dAction() : base()
        {

        }
        public async void ExecCreate(string[] args = null)
        {
            var win = (ILoftDefWindow)AppRuntime.UISystem.CreateWindow("LoftDefSelect");
            var result = AppRuntime.UISystem.ShowDialog(win);
            if (result != LcDialogResult.OK)
            {
                return;
            }
            loftDef = ComponentManager.GetCptDef<LcLoftDef>("放样体", "放样体", win.Uuid);
            if (loftDef == null)
                return;

        }

        private void CreateOrUpdateLoft(Vector3 insertPoint)
        {
            if (this.loft != null)
            {
                this.docRt.Document.ModelSpace.RemoveElement(this.loft);
            }
            var mats = new LcMaterial[1]
            {
                new LcMaterial() { Color = new Color(0xff0000) },
            };

            loft = new LcLoftInstance(null, loftDef);
            loft.Initilize(this.docRt.Document);
            (loft.Rt3DAction as IComponentAction).SetDocEditor(this.docEditor);
            loft.Position.Set(insertPoint.X, insertPoint.Y, insertPoint.Z);
            this.docRt.Document.ModelSpace.InsertElement(loft);
        }
    }
}
